from fastapi import APIRouter, Depends, HTTPException, status, Body
from typing import List,Optional
from .. import schemas
from ..database import get_db
from sqlalchemy.orm import Session
from ..models import User, Notice, Course, CourseCategory, File, Booking, Punch, Schedule
from ..utils.security import decrypt_wechat_phone,code2session
from ..utils.files import get_static_file_url
from datetime import datetime
from sqlalchemy import or_,and_

router = APIRouter(prefix="/api/chance/mp/v1", tags=["authentication"])
phone_cache = {}

# 小程序预登录处理
@router.post("/login", response_model=schemas.MPResponse[dict])
async def do_mp_login(
    payload: schemas.MPLoginRequest = Body(...),
    db: Session = Depends(get_db)
):
    # 使用 Pydantic 模型统一接收前端参数（支持 jsCode / phone）
    jscode = getattr(payload, 'jsCode', '')
    if jscode in phone_cache.keys():
        j_session = phone_cache[jscode]
    else:
        j_session = code2session(jscode)
        phone_cache[jscode]=j_session
    # 如果登录过直接获取用户信息
    phone = getattr(payload, 'phone', '')
    user_info = {}
    if phone:
        existing_user = db.query(User).filter(User.phone == phone).first()
        if existing_user:
            extIconPath = get_static_file_url(getattr(existing_user, 'icon_path', ''))
            user_info = {
                "nickname": existing_user.name,
                "profile":  extIconPath,
                "phone": existing_user.phone,
                "userType": int(existing_user.category),
                "headUrl": extIconPath
            }
    return {"code": 'Success', "msg": "", "data": {"skey": j_session, "userInfo": user_info}}
# 小程序用户注册处理
@router.post("/register", response_model=schemas.MPResponse[dict])
async def do_mp_register(
    payload: schemas.MPRegisterRequest = Body(...),
    db: Session = Depends(get_db)
):
    phone = payload.phone
    nickname = payload.nickname
    profile = payload.profile or ""
    category = payload.category or 0
    skey = payload.skey or ""

    existing_user = db.query(User).filter(User.phone == phone).first()
    from ..utils.security import get_password_hash
    if not existing_user:
        new_user = User(
            username=phone,
            password=get_password_hash('aaAA1234'),
            name=nickname,
            phone=phone,
            category=category,
            icon_path=profile
        )
        db.add(new_user)
        db.commit()
        db.refresh(new_user)

        user_info = {
            "nickname": new_user.name,
            "profile": profile,
            "phone": new_user.phone,
            "userType": int(new_user.category),
            "headUrl": profile
        }
    else:
        extIconPath = get_static_file_url(getattr(existing_user, 'icon_path', ''))
        user_info = {
            "nickname": existing_user.name,
            "profile":  extIconPath,
            "phone": existing_user.phone,
            "userType": int(existing_user.category),
            "headUrl": extIconPath
        }
    phone_cache[skey] = phone
    return {"code": "Success", "msg": "", "data": {"skey": skey, "userInfo": user_info}}
# 小程序用户解码电话处理
@router.post("/decryptPhone", response_model=schemas.MPResponse[dict])
async def do_mp_decrypt_phone(
    payload: schemas.MPDecryptPhoneRequest = Body(...)
):
    skey = payload.skey
    if skey in phone_cache.keys():
        phoneData = phone_cache[skey]
    else:
        try:
            # 电话密纹数据解码
            phoneData = decrypt_wechat_phone(payload.phoneData,payload.phoneDataIV,skey)
            # phoneData = '18981905727'
        except Exception as e:
            raise HTTPException(status_code=500, detail="解码电话失败.")    
    return {"code": "Success", "msg": "", "data": {"phoneNumber": phoneData}}
# 获取课程列表
@router.post("/courses/list", response_model=schemas.MPResponse[dict])
async def get_courses_list(
    payload: schemas.MPSearchRequest = Body(...),
    db: Session = Depends(get_db)
):
    offset = payload.offset or 0
    limit = payload.limit or 10
    searchKey = payload. searchKey or ""

    query = db.query(Course)
    
    if searchKey:
        query = query.filter(Course.title.contains(searchKey))
    
    # 查询所有课程
    courses = query.offset(offset).limit(limit).all()
    
    # 转换为返回格式
    courses_list = []
    for course in courses:
        cover_url = get_static_file_url(course.cover) if course.cover else ""
        courses_list.append({
            "courseId": course.id,
            "cover": cover_url,
            "title": course.title,
            "desc": course.desc or "",
            "price": course.price / 100.0,  # 转换为元
            "bookNum": course.book_num
        })
    
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": {
            "courses": courses_list,
            "total": len(courses_list)
        }
    }
#  获取课程详情
@router.post("/courses/detail", response_model=schemas.MPResponse[dict])
async def get_courses_detail(
    payload: schemas.MPBaseIdRequest = Body(...),
    db: Session = Depends(get_db)
):
    course_id = int(payload.baseId)
        
    # 查询课程
    course = db.query(Course).filter(Course.id == course_id, Course.is_active == True).first()
    
    if not course:
        raise HTTPException(status_code=404, detail="课程不存在")
    
    # 查询课程章节
    categories = db.query(CourseCategory).filter(
        CourseCategory.course_id == course_id,
        CourseCategory.is_active == True
    ).order_by(CourseCategory.sort_order).all()

    #  参数用户权限处理，只有学生和老师身份才能看第一章以外的。
    userType = payload.userType or 0

    # 转换章节数据
    categories_list = []
    for category in categories:
        canView = category.sort_order == 1 or userType == 1
        categories_list.append({
            "code": category.code,
            "name": category.name,
            "canView": canView,
            "content": category.content or "",
            "url": get_static_file_url(category.url) or ""
        })
    
    # 获取封面URL
    cover_url = get_static_file_url(course.cover) if course.cover else ""
    
    return {
        "code": "Success",
        "msg": "请求成功",
        "data": {
            "courseId": course.id,
            "cover": cover_url,
            "title": course.title,
            "desc": course.desc or "",
            "price": course.price / 100.0,  # 转换为元
            "categories": categories_list
        }
    }
# 获取视频列表
@router.post("/videos/list", response_model=schemas.MPResponse[dict])
async def get_videos_list(
    payload: schemas.MPSearchRequest = Body(...),
    db: Session = Depends(get_db)
):
    offset = payload.offset or 0
    limit = payload.limit or 10
    searchKey = payload. searchKey or ""

    query = db.query(File)

    # 只查询视频文件
    query = query.filter(File.file_type == "视频")
    
    if searchKey:
        query = query.filter(File.display_name.contains(searchKey))
    
    # 查询所有课程
    videos = query.offset(offset).limit(limit).all()
    
    # 转换为返回格式
    videos_list = []
    for video in videos:
        videos_list.append({
            "videoId": video.id,
            "title": video.display_name,
            "watchNum": video.watch_num,
            "desc": video.description,
            "url": get_static_file_url(video.saved_filename)
        })
    
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": {
            "videos": videos_list,
            "total": len(videos_list)
        }
    }
# 更新视频次数
@router.post("/videos/update", response_model=schemas.MPResponse[dict])
async def get_videos_list(
    payload: schemas.MPBaseIdRequest = Body(...),
    db: Session = Depends(get_db)
):
    baseId = payload.baseId
    if not baseId:
        raise HTTPException(status_code=404, detail="视频不存在")

    # 查询视频
    file = db.query(File).filter(File.id == baseId).first()
    if not file:
        raise HTTPException(status_code=404, detail="视频不存在")
    
    # 转换为返回格式
    setattr(file, 'watch_num', file.watch_num + 1)
    db.commit()
    db.refresh(file)
    
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200
    }

# 获取轮播图信息
@router.post("/notify", response_model=schemas.MPResponse[list])
async def get_notify(
    db: Session = Depends(get_db)
):
    # 查询所有轮播图和广告的数据
    notices = db.query(Notice).filter(Notice.type == 2).all()
        
    # 转换为返回格式
    data = []
    for notice in notices:
        data.append({
            "url": get_static_file_url(notice.icon_path),
            "type": 3,
            "h5Url": notice.link_url
        })

    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": data
    }
def model_to_dict(model):
    return {c.name: getattr(model, c.name) for c in model.__table__.columns}
# 获取置顶信息
@router.post("/queryMpHomeList", response_model=schemas.MPResponse[list])
async def get_mp_home_list(
    db: Session = Depends(get_db)
):
    # 查询最新一个系统消息的数据
    notice = db.query(Notice).filter(Notice.type == 0).order_by(Notice.pushTime.desc()).first()
    data = {}
    if notice:
        # 转换为返回格式
        data = [{
            "id": notice.id,
            "icon": get_static_file_url(notice.icon_path),
            "title": notice.title,
            "pushOrg": notice.pushOrg,
            "pushTime": datetime.strptime(str(notice.pushTime), "%Y-%m-%d %H:%M:%S.%f").strftime("%Y-%m-%d"),
            "type": notice.type
        }]

    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": data
    }
# 获取用户消息
@router.post('/messages/list', response_model=schemas.MPResponse[dict])
async def get_messages_list(
    payload: schemas.MPPhoneRequest = Body(...),
    db: Session = Depends(get_db)
):
    # notice表中type为0的所有系统消息
    notices = db.query(Notice).filter(Notice.type == 0).all()
    # notice表中type为1的并且id是在booking表中与当前用户关联的消息
    userPhone = payload.phoneNumber
    bookings = db.query(Booking).filter(or_(Booking.from_phone == userPhone,Booking.to_phone == userPhone)).all()
    link_notices_ids = []
    for book in bookings:
        link_notices_ids.append(book.notice_id)
    # notice表中type为1的并且id是在punch表中与当前用户关联的消息
    punchs = db.query(Punch).filter(Punch.phone == userPhone).all()
    for punch in punchs:
        link_notices_ids.append(punch.notice_id)
    # notice表中type为1的并且id是在schdule表中与当前用户关联的消息
    schedules = db.query(Schedule).filter(Schedule.phone == userPhone).all()
    for schedule in schedules:
        link_notices_ids.append(schedule.notice_id)
    # 查找消息相关内容
    if link_notices_ids:
        other_otices = db.query(Notice).filter(Notice.id.in_(link_notices_ids)).all()
        notices.extend(other_otices)
    
    # 转换为返回格式
    notices_list = []
    for notice in notices:
        notices_list.append({
            "id": notice.id,
            "content": notice.pushOrg,
            "timestamp": datetime.strptime(str(notice.pushTime), "%Y-%m-%d %H:%M:%S.%f").strftime("%Y-%m-%d %H:%M:%S"),
        })
    
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": {
            "messages": notices_list,
        }
    }
# 获取教务人员列表
@router.post("/affairs/list", response_model=schemas.MPResponse[dict])
async def get_affairs_list(
    payload: schemas.MPSearchRequest = Body(...),
    db: Session = Depends(get_db)
):
    offset = payload.offset or 0
    limit = payload.limit or 10

    query = db.query(User)
    # 添加教务人员过滤条件
    query = query.filter(and_(User.category == '3', User.sec_type == 0))
    users = query.offset(offset).limit(limit).all()

    affairs = []
    for user in users:
        affairs.append({
            "id": user.id,
            "cover": get_static_file_url(user.icon_path),
            "name": user.name,
            "desc": user.desc,
            "phone": user.phone
        })
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": {
            "affairs": affairs,
             "total": len(affairs)
        }
    }
# 获取顾问人员列表
@router.post("/advisors/list", response_model=schemas.MPResponse[dict])
async def get_advisors_list(
    payload: schemas.MPSearchRequest = Body(...),
    db: Session = Depends(get_db)
):
    offset = payload.offset or 0
    limit = payload.limit or 10

    query = db.query(User)
    # 添加教务人员过滤条件
    query = query.filter(and_(User.category == '3', User.sec_type == 1))
    users = query.offset(offset).limit(limit).all()

    advisors = []
    for user in users:
        advisors.append({
            "id": user.id,
            "cover": get_static_file_url(user.icon_path),
            "name": user.name,
            "desc": user.desc,
            "phone": user.phone
        })
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": {
            "advisors": advisors,
             "total": len(advisors)
        }
    }
# 预约上课
@router.post('/booking/teach', response_model=schemas.MPResponse[dict])
async def do_booking_teach(
    payload: schemas.MPBookingTeachRequest = Body(...),
    db: Session = Depends(get_db)
):
    from_phone = payload.userPhone
    book_date = payload.selectDate
    affairsId = payload.affairsId 
    
    # 1. 验证预约者是学生
    student = db.query(User).filter(
        User.phone == from_phone,
        User.category == '1'
    ).first()
    
    if not student:
        raise HTTPException(status_code=500, detail="用户不是有效的学生")
    
    # 2. 验证预约对象是老师
    teacher = db.query(User).filter(
        User.id == affairsId,
        User.category == '3'
    ).first()
    
    if not teacher:
        raise HTTPException(status_code=500, detail="预约对象不是老师")
    
    # 3. 创建通知消息
    notice_title = "预约上课"
    notice_content = f"学员{student.name}已成功预约{teacher.name}老师在{book_date}的课程。"
    
    new_notice = Notice(
        title=notice_title,
        pushOrg=notice_content,
        pushTime=datetime.now(),
        type=1, # 用户消息
        is_active=True
    )
    
    db.add(new_notice)
    db.commit()
    db.refresh(new_notice)
    
    # 4. 创建预约记录
    new_booking = Booking(
        from_phone=from_phone,
        book_date=book_date,
        to_phone=teacher.phone,
        notice_id=new_notice.id,
    )
    
    db.add(new_booking)
    db.commit()
    db.refresh(new_booking)
    
    return {
        "code": "Success",
        "msg": "预约成功",
        "statusCode": 200,
        "data": {
            "bookingId": new_booking.id,
            "noticeId": new_notice.id
        }
    }
# 学习情况
@router.post('/study/info', response_model=schemas.MPResponse[dict])
async def get_study_info(
    payload: schemas.MPPhoneRequest = Body(...),
    db: Session = Depends(get_db)
):
    # TODO
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": {
            "joinDay": 1,  # 加入天数
            "studyDay": 1, # 学习天数
            "records": ["单课","单词打卡","N1考试"], # 学习记录标签
            "statics": {
                "studyDuration": 360, # 累计学习时长
                "finishedCourses": 23, # 累计完成课程
                "dayStudyDuration": 15, # 日学习时长
                "dayFinishedCourses": 0, # 日完成课程
                "weekStudyDuration": 90, # 周学习时长
                "weekFinishedCourses": 3, # 周完成课程
                "monthStudyDuration": 190, # 月学习时长
                "monthFinishedCourses": 12 # 月完成课程
            }
        }
    }
# 获取打卡单词集
@router.post('/study/punchWords', response_model=schemas.MPResponse[dict])
async def get_study_punchWords(
    db: Session = Depends(get_db)
):
    # TODO
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": {
            "words": [
                {
                    "id": 1,
                    "word": "こんにちは",
                    "translation": "你好",
                    "example": "こんにちは、元気ですか？"
                },
                {
                    "id": 2,
                    "word": "さようなら",
                    "translation": "再见",
                    "example": "さようなら、また会いましょう。"
                }
            ]
        }
    }
# 打卡单词
@router.post('/study/submitPunchWords', response_model=schemas.MPResponse[dict])
async def do_study_punchWords(
    payload: schemas.MPSubmitPunchWordsRequest = Body(...),
    db: Session = Depends(get_db)
):
    phone = payload.phone
    
    # 1. 验证用户是学生
    student = db.query(User).filter(
        User.phone == phone,
        User.category == '1'
    ).first()
    
    if not student:
        raise HTTPException(status_code=400, detail="用户不是有效的学生")
    
    # 获取当天日期
    today = datetime.now().strftime('%Y-%m-%d')
    
    # 2. 创建通知消息
    notice_title = "单词打卡"
    notice_content = f"学员{student.name}完成{today}的单词打卡。"
    
    new_notice = Notice(
        title=notice_title,
        pushOrg=notice_content,
        pushTime=datetime.now(),
        type=1,
        is_active=True
    )
    
    db.add(new_notice)
    db.commit()
    db.refresh(new_notice)
    
    # 3. 创建打卡记录
    new_punch = Punch(
        phone=phone,
        punch_date=today,
        notice_id=new_notice.id,
        type=0,  # 0-单词打卡
    )
    
    db.add(new_punch)
    db.commit()
    db.refresh(new_punch)
    
    return {
        "code": "Success",
        "msg": "打卡成功",
        "statusCode": 200,
        "data": {
            "punchId": new_punch.id,
            "noticeId": new_notice.id,
            "punchDate": today
        }
    }
# 提交添加课程
@router.post('/courses/add', response_model=schemas.MPResponse[dict])
async def do_courses_add(
    payload: schemas.MPCoursesAddRequest = Body(...),
    db: Session = Depends(get_db)
):
    phone = payload.phone
    newCourse = payload.newCourse  # 课程对象，前端传 JSON
    
    # 1. 验证用户是老师
    teacher = db.query(User).filter(
        User.phone == phone,
        User.category == '3'
    ).first()
    
    if not teacher:
        raise HTTPException(status_code=500, detail="用户不是有效的教师")
    
    # 从newCourse中获取课程信息
    course_name = newCourse.get('courseName', '')
    date = newCourse.get('date', '')
    time_slot = newCourse.get('timeSlot', '')
    
    if not course_name or not date or not time_slot:
        raise HTTPException(status_code=500, detail="课程信息不完整")
    
    # 2. 创建通知消息
    notice_title = "老师排课"
    notice_content = f"老师{teacher.name}新增加了{date}在时间段{time_slot}的排课。"
    
    new_notice = Notice(
        title=notice_title,
        pushOrg=notice_content,
        pushTime=datetime.now(),
        type=1,
        is_active=True
    )
    
    db.add(new_notice)
    db.commit()
    db.refresh(new_notice)
    
    # 3. 创建排课记录
    new_schedule = Schedule(
        phone=phone,
        course_name=course_name,
        date=date,
        time_slot=time_slot,
        notice_id=new_notice.id
    )
    
    db.add(new_schedule)
    db.commit()
    db.refresh(new_schedule)
    
    return {
        "code": "Success",
        "msg": "排课成功",
        "statusCode": 200,
        "data": {
            "scheduleId": new_schedule.id,
            "noticeId": new_notice.id,
        }
    }
# 获取当周课程表
@router.post('/courses/schedule', response_model=schemas.MPResponse[dict])
async def get_courses_schedule(
    payload: schemas.MPTodayRequest = Body(...),
    db: Session = Depends(get_db)
):
    from datetime import timedelta
    
    # 获取今天的日期
    today = datetime.strptime(payload.today,'%Y-%m-%d').date() or datetime.now().date()
    # 计算七天后的日期
    seven_days_later = today + timedelta(days=7)
    
    # 转换为字符串格式
    today_str = today.strftime('%Y-%m-%d')
    seven_days_later_str = seven_days_later.strftime('%Y-%m-%d')
    
    # 查询今天到七天后的排课记录
    schedules = db.query(Schedule).filter(
        Schedule.date >= today_str,
        Schedule.date <= seven_days_later_str,
    ).order_by(Schedule.date, Schedule.time_slot).all()
    
    # 构建返回数据
    schedule_list = []
    for schedule in schedules:
        # 根据phone查询老师信息
        teacher = db.query(User).filter(
            User.phone == schedule.phone,
            User.category == '3'
        ).first()
        
        teacher_name = teacher.name if teacher else "未知老师"
        
        schedule_list.append({
            "id": schedule.id,
            "date": schedule.date,
            "courseName": schedule.course_name,
            "teacher": teacher_name,
            "timeSlot": schedule.time_slot
        })
    
    return {
        "code": "Success",
        "msg": "请求成功",
        "statusCode": 200,
        "data": {
            "schedule": schedule_list
        }
    }